﻿using System;
using System.Collections.Generic;
using Needle.Bus.Configuration;
using Needle.Bus.Engine.Queues;
using Needle.Bus.Engine.Stages;
using Needle.Bus.Engine.Utils;

namespace Needle.Bus.Engine.Factories
{

    public class StageFactory : IFactory<IStage>
    {

        BusConfiguration _config;
        IFactory<IStageFilter> _filterLoader;
        IFactory<IMessageHandler> _handlerLoader;
        IFactory<IPerformanceCounter> _perfCounterLoader;

        public StageFactory(
            BusConfiguration config,
            IFactory<IStageFilter> filterLoader,
            IFactory<IMessageHandler> handlerLoader,
            IFactory<IPerformanceCounter> perfCounterLoader)
        {
            if (config == null)
                throw new ArgumentNullException("config", "config is null.");
            if (filterLoader == null)
                throw new ArgumentNullException("filterLoader", "filterLoader is null.");
            if (handlerLoader == null)
                throw new ArgumentNullException("handlerLoader", "handlerLoader is null.");
            if (perfCounterLoader == null)
                throw new ArgumentNullException("perfCounterLoader", "perfCounterLoader is null.");

            _config = config;
            _filterLoader = filterLoader;
            _handlerLoader = handlerLoader;
            _perfCounterLoader = perfCounterLoader;
        }

        public IList<IStage> CreateAll()
        {
            List<IStage> stages = new List<IStage>();

            foreach (var stageConfig in _config.Stages)
            {
                var stage = Create(stageConfig.Id);
                stages.Add(stage);
            }
            return stages;
        }

        public IStage Create(string id)
        {
            StageConfiguration cfg = null;
            if (_config.Stages.TryGetValue(id, out cfg))
            {
                var mutex = new NamedMutex(cfg.Id + " Mutex");
                var buffer = new BufferQueue(mutex, cfg.Id);
                var filter = _filterLoader.Create(cfg.Filter);
                var handler = _handlerLoader.Create(cfg.Handler);
                var perfCounter = _perfCounterLoader.Create(cfg.Id);

                var newStage = new Stage(mutex, cfg.Id, buffer,
                                           filter, handler, perfCounter);

                newStage.BatchMode = new BatchModeOptions(cfg.BatchMode, 
                                            cfg.MinBatchSize, cfg.MaxBatchSize);
                return newStage;
            }
            throw new ArgumentException("Unknown stage id " + id, "id");
        }
    }
}
